package model.algorithm;

import java.util.NoSuchElementException;

import model.datastructure.BlockSurface2D;
import model.datastructure.FieldSurface2D;
import model.datastructure.ISurface;

public class PartitionedSteppingIterator extends AbstractSurfaceIterator {

	/**
	 * Contains the exclusive end of each partition
	 * For example: take a fieldwidth of 10 and a partitionsize of 5
	 * partitions will have a length of 2. partitions[0] will be 5, and partitions[1] will be 10
	 * If fieldWidth % partitionSize != 0, the last partition will be the smallest
	 */
	private int[] partitions;
	private int currentPartition = 0;
	private int fieldWidth;
	private int blockWidth;
	private int partitionSize;

	/**
	 * Constructor
	 * 
	 * @param fieldWidth
	 * @param partitionSize
	 */
	public PartitionedSteppingIterator(int fieldWidth, int partitionSize) {
		assert(fieldWidth >= partitionSize);
		this.partitionSize = partitionSize;
		this.fieldWidth = fieldWidth;
		createPartitions();
		name = "Part It";
	}
	
	@Override
	public boolean hasNext() {
		return index <= partitions[currentPartition] - blockWidth;
	}

	@Override
	public Integer next() {
		if (!hasNext()){
			throw new NoSuchElementException("Please use the hasNext() method, dimwit");
		}
		return index++;
	}

	@Override
	/**
	 * Does nothing
	 */
	public void remove() {
		// do nothing
	}

	@Override
	public void reset(FieldSurface2D fieldSurface, ISurface blockSurface, boolean isLookahead) {
		fieldWidth = fieldSurface.getWidth();
		blockWidth = ( ( BlockSurface2D ) blockSurface ).getWidth();
		if (!isLookahead) {
			currentPartition++;
		}
		if (currentPartition == partitions.length) {
			currentPartition = 0;
			index = 0;	
		} else if (currentPartition == 0) {
			index = 0;	
		} else {
			index = partitions[currentPartition-1];
		}
	}
	
	/**
	 * Divides the field up in partitions to iterate over
	 * For example: take a fieldwidth of 10 and a partitionsize of 5
	 * partitions will have a length of 2. partitions[0] will be 5, and partitions[1] will be 10
	 * If fieldWidth % partitionSize != 0, the last partition will be the smallest
	 */
	private void createPartitions() {
		int numberOfPartitions = fieldWidth / partitionSize;
		partitions = new int[numberOfPartitions];
		for (int i = 0; i < partitions.length-1; i++) {
			partitions[i] = partitionSize * (i+1);			
		}
		partitions[partitions.length-1] = fieldWidth;
		//System.out.println(Arrays.toString(partitions));
	}
	
	@Override
	public String toString() {
		return super.toString() + "(" + partitionSize + ")";
	}

	@Override
	public int getFieldWidth() {
		return partitionSize;
	}
	
	@Override
	public int getLookaheadBlockStepSize() {
		return partitions.length;
	}
	
}
